package com.yf.course.modules.course.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yf.base.api.api.dto.PagingReqDTO;
import com.yf.base.enums.OpenType;
import com.yf.base.utils.BeanMapper;
import com.yf.base.utils.CronUtils;
import com.yf.base.utils.DecimalUtils;
import com.yf.course.job.CourseNotifyJob;
import com.yf.course.modules.course.dto.CourseDTO;
import com.yf.course.modules.course.dto.CourseRefPointDTO;
import com.yf.course.modules.course.dto.KnowledgePointDTO;
import com.yf.course.modules.course.dto.ext.*;
import com.yf.course.modules.course.dto.request.CourseNotifyReqDTO;
import com.yf.course.modules.course.dto.request.UserCourseReqDTO;
import com.yf.course.modules.course.dto.response.UserCourseRespDTO;
import com.yf.course.modules.course.entity.*;
import com.yf.course.modules.course.mapper.CourseMapper;
import com.yf.course.modules.course.mapper.CourseRepoMapper;
import com.yf.course.modules.course.mapper.CourseSpeechMapper;
import com.yf.course.modules.course.mapper.SpeechMapper;
import com.yf.course.modules.course.service.*;
import com.yf.course.modules.course.utils.CourseStateUtils;
import com.yf.job.service.JobService;
import com.yf.repo.modules.qu.entity.Qu;
import com.yf.repo.modules.qu.mapper.QuMapper;
import com.yf.system.modules.user.UserUtils;
import com.yf.system.modules.user.entity.SysRole;
import com.yf.system.modules.user.entity.SysUser;
import com.yf.system.modules.user.mapper.SysRoleMapper;
import com.yf.system.modules.user.service.SysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程信息业务实现类
 * </p>
 *
 * @author 聪明笨狗
 * @since 2020-12-17 11:28
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {

    @Autowired
    private CourseRefFileService courseRefFileService;

    @Autowired
    private CourseFileService courseFileService;

    @Autowired
    private CourseRefDirService courseRefDirService;

    @Autowired
    private CourseRefPointService courseRefPointService;

    @Autowired
    private CourseLearnService courseLearnService;

    @Autowired
    private CourseDepartService courseDepartService;

    @Autowired
    private CoursePersonService coursePersonService;

    @Autowired
    private CourseLiveService courseLiveService;

    @Autowired
    private CourseLearnDailyService courseLearnDailyService;

    @Autowired
    private JobService jobService;

    @Autowired
    private CourseStateUtils courseStateUtils;

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CourseSpeechMapper courseSpeechMapper;

    @Autowired
    private SpeechMapper speechMapper;

    @Autowired
    private QuMapper quMapper;

    @Autowired
    private CourseRepoMapper courseRepoMapper;

    @Override
    public IPage<CourseDTO> paging(PagingReqDTO<CourseDTO> reqDTO) {

        // 创建分页对象
        Page query = reqDTO.toPage();


        //查询条件
        QueryWrapper<Course> wrapper = new QueryWrapper<>();

        // 请求参数
        CourseDTO params = reqDTO.getParams();

        if (params != null) {
            if (params.getIsMust() != null) {
                wrapper.lambda().eq(Course::getIsMust, params.getIsMust());
            }

            if (!StringUtils.isBlank(params.getCatId())) {
                wrapper.lambda().eq(Course::getCatId, params.getCatId());
            }

            if (!StringUtils.isBlank(params.getTitle())) {
                wrapper.lambda().like(Course::getTitle, params.getTitle());
            }
        }
        // 权限逻辑
        String currentUserId = UserUtils.getUserId();
        // 空用户直接返回空分页，避免 NPE
        if (StringUtils.isBlank(currentUserId)) {
            return new Page<>();
        }
        //获取用户部门
        SysUser sysUser = sysUserService.getById(currentUserId);
        if (sysUser == null) {
            return new Page<>();
        }
        String deptCode = sysUser.getDeptCode();
        if (StringUtils.isBlank(deptCode)) {
            return new Page<>();
        }
        //根据部门查找课程部门映射
        List<CourseDepart> courseDepartList = courseDepartService.list(
                new QueryWrapper<CourseDepart>().eq("dept_code", deptCode));
        //获取课程id
        List<String> courseId = courseDepartList.stream()
                .map(CourseDepart::getCourseId)
                .collect(Collectors.toList());
        //管理员
        boolean isAdmin = UserUtils.getRoleLevel() > 3;
        if (isAdmin) {
            //如果是管理员，并且自己写了查询条件，按照查询条件找
            if (params != null && !StringUtils.isBlank(params.getCreateBy())) {
                wrapper.eq("create_by", params.getCreateBy());
            }
        } else {
            // 用部门代码过滤普通用户数据
            //直接查deptCode是按照 el_course 查
            //wrapper.eq("dept_code", deptCode);
            if (!courseId.isEmpty()) {
                wrapper.in("id", courseId);
            } else {
                return new Page<>();
            }
        }

        boolean addPriorityOrder;
        if (isAdmin) {
            // 管理员在未指定createBy时添加优先排序
            addPriorityOrder = params == null || StringUtils.isBlank(params.getCreateBy());
        } else {
            // 普通用户始终添加优先排序
            addPriorityOrder = true;
        }
        if (addPriorityOrder && StringUtils.isNotBlank(currentUserId)) {
            // 优先显示当前用户创建的课程
            wrapper.orderByDesc("(create_by = '" + currentUserId + "')");
        }

        wrapper.lambda().orderByAsc(Course::getCreateTime);

        IPage<Course> page = this.page(query, wrapper);

        IPage<CourseDTO> pageData = new Page<>();
        pageData.setCurrent(page.getCurrent());
        pageData.setSize(page.getSize());
        pageData.setTotal(page.getTotal());
        if (isAdmin){
            pageData.setRecords(
                    page.getRecords().stream().map(course -> {
                        CourseDTO dto = new CourseDTO();
                        BeanUtils.copyProperties(course, dto);
                        dto.setIsCurrentVisible(true);
                        return dto;
                    }).collect(Collectors.toList())
            );
        }else{
            pageData.setRecords(
                    page.getRecords().stream().map(course -> {
                        CourseDTO dto = new CourseDTO();
                        BeanUtils.copyProperties(course, dto);
                        dto.setIsCurrentVisible(course.getCreateBy().equals(currentUserId));
                        return dto;
                    }).collect(Collectors.toList())
            );
        }
        return pageData;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(CourseDetailExtDTO reqDTO) {


        // 原来的ID
        String oriId = reqDTO.getId();
        if (oriId.startsWith("temp_")) {
            reqDTO.setId(null);
        }

        System.out.println("++++++++++++oriId:" + oriId);

        // 保存基本信息
        Course entity = new Course();
        BeanMapper.copy(reqDTO, entity);
        // 基础状态不变化
        entity.setState(null);
        // 添加修改模式
        boolean add = false;
        if (StringUtils.isBlank(entity.getId())) {
            add = true;
            entity.setId(IdWorker.getIdStr());
        }

        try {
            // 通过定时任务解耦
            jobService.addCronJob(Class.forName("com.yf.exam.job.HideExamJob"), null, entity.getRefExam());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

        // 保存课件引用
        List<CourseRefDirExtDTO> dirList = reqDTO.getDirList();

        //知识点列表
        List<CourseRefPointDTO> pointList = reqDTO.getPointList();

        // 保存对象列表
        List<CourseRefDir> saveDirs = new ArrayList<>();
        List<CourseRefPoint> savePoints = new ArrayList<>();
        List<CourseRefFile> saveFiles = new ArrayList<>();

        List<CourseFile> courseFiles = new ArrayList<>();

        BigDecimal time = DecimalUtils.zero();


        // 文件排序，解锁要用到
        int sort = 1;

        // 非空才处理
        if (!CollectionUtils.isEmpty(dirList)) {
            int i = 1;
            for (CourseRefDirExtDTO item : dirList) {
                CourseRefDir dir = new CourseRefDir();
                dir.setId(IdWorker.getIdStr());
                dir.setCourseId(entity.getId());
                dir.setTitle(item.getTitle());
                dir.setSort(i);
                dir.setDesKnowledge(item.getDesKnowledge());
                saveDirs.add(dir);

                List<CourseRefFileExtDTO> fileList = item.getFileList();

                if (CollectionUtils.isEmpty(fileList)) {
                    continue;
                }


                for (CourseRefFileExtDTO item1 : fileList) {
                    CourseRefFile file = new CourseRefFile();
                    file.setDirId(dir.getId());
                    file.setCourseId(entity.getId());
                    file.setFileId(item1.getFileId());
                    file.setNeedLearn(item1.getNeedLearn());
                    file.setPoints(item1.getPoints());
                    file.setSort(sort);
                    saveFiles.add(file);
                    sort++;
                    // 总课时
                    time = DecimalUtils.add(time, new BigDecimal(file.getNeedLearn()));

                    CourseFile course = courseFileService.getById(item1.getFileId());
                    course.setTitle(item1.getTitle());
                    courseFiles.add(course);
                }
            }
        }

        if (!CollectionUtils.isEmpty(pointList)) {
            int i = 1;
            for (CourseRefPointDTO item : pointList) {
                CourseRefPoint point = new CourseRefPoint();
                point.setId(IdWorker.getIdStr());
                point.setCourseId(entity.getId());
                point.setTitle(item.getTitle());
                point.setSort(i);
                point.setDesKnowledge(item.getDesKnowledge());
                savePoints.add(point);

            }
        }

        // 更新课时数量，45分钟为1课时
        if (entity.getPeriods() == null || entity.getPeriods().equals(0)) {
            BigDecimal periods = DecimalUtils.divide(time, 60 * 45);
            entity.setPeriods(periods.intValue());
        }

        if (add) {
            save(entity);
        } else {
            updateById(entity);
        }


        // 保存部门映射
        if (OpenType.DEPART.equals(entity.getOpenType())) {
            courseDepartService.saveAll(entity.getId(), reqDTO.getDeptCodes());
        }

        // 更新人员映射
        if (OpenType.PERSON.equals(entity.getOpenType())) {
            coursePersonService.modifyAll(oriId, entity.getId());
        }

        // 保存直播课程
        courseLiveService.saveAll(entity.getId(), reqDTO.getLiveList());

        // 保存目录
        courseRefDirService.save(entity.getId(), saveDirs);

        //保存知识点
        courseRefPointService.save(entity.getId(), savePoints);

        // 保存文件
        courseRefFileService.save(entity.getId(), saveFiles);
        courseFileService.batchSave(courseFiles);

        // 更新学员的学习进度
        courseLearnService.reCheck(entity.getId());

    }

    @Override
    public CourseDetailExtDTO detail(String id) {

        CourseDetailExtDTO respDTO = baseMapper.findDetail(id);

        // 学员端限制
        if (UserUtils.isStudent()) {
            // 未开始或已结束
            if (!respDTO.getState().equals(0)) {
                respDTO.setDirList(new ArrayList<>());
            }
        }

        // 是否购买
        boolean isBuy = true;
        respDTO.setIsBuy(isBuy);
        if (!isBuy) {
            respDTO.setDirList(new ArrayList<>());
        }

        // 每日限制时间
        if (respDTO.getDayLimit() != null && respDTO.getDayLimit() > 0) {
            long learnSec = courseLearnDailyService.daily(id, UserUtils.getUserId());
            respDTO.setLearnMin((int) (learnSec / 60));
        }

        if (!StringUtils.isBlank(respDTO.getRefExam())) {
            boolean finished = courseLearnService.finished(id, UserUtils.getUserId());
            respDTO.setFinished(finished);
        }


        // 设置状态
        int state = courseStateUtils.modifyState(id,
                respDTO.getState(),
                UserUtils.getUserId(),
                respDTO.getOpenType(),
                respDTO.getDayLimit(),
                respDTO.getStartTime(),
                respDTO.getEndTime(),
                respDTO.getDayRule());


        // 设置状态
        respDTO.setState(state);

        // 设置讲稿
        try {
            String speechId = courseSpeechMapper.selectById(respDTO.getId()).getSpeechId();
            respDTO.setSpeechText(speechMapper.selectById(speechId).getSpeechText());
        }catch(Exception e){
            respDTO.setSpeechText("");
        }

        return respDTO;
    }

    @Override
    public IPage<UserCourseRespDTO> userPaging(PagingReqDTO<UserCourseReqDTO> reqDTO) {
        return baseMapper.userPaging(reqDTO.toPage(), reqDTO.getParams());
    }

    @Override
    public int canLearn(Course course, String userId) {

        // 设置状态
        int state = courseStateUtils.modifyState(course.getId(),
                course.getState(),
                userId,
                course.getOpenType(),
                course.getDayLimit(),
                course.getStartTime(),
                course.getEndTime(),
                course.getDayRule());

        return state;
    }

    @Override
    public Course findSimple(String courseId) {

        QueryWrapper<Course> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .select(Course::getId,
                        Course::getOpenType,
                        Course::getStartTime,
                        Course::getEndTime,
                        Course::getDayRule,
                        Course::getDayLimit,
                        Course::getStepLock,
                        Course::getState)
                .eq(Course::getId, courseId);

        return this.getOne(wrapper, false);
    }


    @Override
    public void prepareNotify(CourseNotifyReqDTO reqDTO) {
        // 立即触发
        if ("1".equalsIgnoreCase(reqDTO.getTrigger())) {
            jobService.addCronJob(CourseNotifyJob.class, null, JSON.toJSONString(reqDTO));
        } else {
            jobService.addCronJob(CourseNotifyJob.class, null, CronUtils.dateToCron(reqDTO.getSendTime()), JSON.toJSONString(reqDTO));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String saveById(CourseDetailExtDTO reqDTO) {
        // 原来的ID
        String oriId = reqDTO.getId();
        if (oriId.startsWith("temp_")) {
            reqDTO.setId(null);
        }

        System.out.println("++++++++++++oriId:" + oriId);

        // 保存基本信息
        Course entity = new Course();
        BeanMapper.copy(reqDTO, entity);
        // 基础状态不变化
        entity.setState(null);
        // 添加修改模式
        boolean add = false;
        String returnId = IdWorker.getIdStr();
        if (StringUtils.isBlank(entity.getId())) {
            add = true;
            entity.setId(returnId);
        }

        try {
            // 通过定时任务解耦
            jobService.addCronJob(Class.forName("com.yf.exam.job.HideExamJob"), null, entity.getRefExam());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

        // 保存课件引用
        List<CourseRefDirExtDTO> dirList = reqDTO.getDirList();

        // 报错对象列表
        List<CourseRefDir> saveDirs = new ArrayList<>();
        List<CourseRefFile> saveFiles = new ArrayList<>();

        BigDecimal time = DecimalUtils.zero();


        // 文件排序，解锁要用到
        int sort = 1;

        // 非空才处理
        if (!CollectionUtils.isEmpty(dirList)) {
            int i = 1;
            for (CourseRefDirExtDTO item : dirList) {
                CourseRefDir dir = new CourseRefDir();
                dir.setId(IdWorker.getIdStr());
                dir.setCourseId(entity.getId());
                dir.setTitle(item.getTitle());
                dir.setSort(i);
                saveDirs.add(dir);

                List<CourseRefFileExtDTO> fileList = item.getFileList();

                if (CollectionUtils.isEmpty(fileList)) {
                    continue;
                }


                for (CourseRefFileExtDTO item1 : fileList) {
                    CourseRefFile file = new CourseRefFile();
                    file.setDirId(dir.getId());
                    file.setCourseId(entity.getId());
                    file.setFileId(item1.getFileId());
                    file.setNeedLearn(item1.getNeedLearn());
                    file.setPoints(item1.getPoints());
                    file.setSort(sort);
                    saveFiles.add(file);
                    sort++;
                    // 总课时
                    time = DecimalUtils.add(time, new BigDecimal(file.getNeedLearn()));
                }
            }
        }

        // 更新课时数量，45分钟为1课时
        if (entity.getPeriods() == null || entity.getPeriods().equals(0)) {
            BigDecimal periods = DecimalUtils.divide(time, 60 * 45);
            entity.setPeriods(periods.intValue());
        }

        if (add) {
            save(entity);
        } else {
            updateById(entity);
        }


        // 保存部门映射
        if (OpenType.DEPART.equals(entity.getOpenType())) {
            courseDepartService.saveAll(entity.getId(), reqDTO.getDeptCodes());
        }

        // 更新人员映射
        if (OpenType.PERSON.equals(entity.getOpenType())) {
            coursePersonService.modifyAll(oriId, entity.getId());
        }

        // 保存直播课程
        courseLiveService.saveAll(entity.getId(), reqDTO.getLiveList());

        // 保存目录
        courseRefDirService.save(entity.getId(), saveDirs);

        // 保存文件
        courseRefFileService.save(entity.getId(), saveFiles);

        // 更新学员的学习进度
        courseLearnService.reCheck(entity.getId());
        return returnId;
    }

    @Override
    public void saveByExam(CourseDetailExtDTO detail) {
        courseMapper.saveByExam(detail.getRefExam(), detail.getId());
    }

    @Override
    public void addCourseKnowledgePoint(KnowledgePointDTO knowledgePointDTO) {
        try {
            String courseId = knowledgePointDTO.getCourseId();
            String desKnowledge = knowledgePointDTO.getPoint();


            CourseRefPoint courseRefPoint = courseRefPointService.lambdaQuery().eq(CourseRefPoint::getCourseId, courseId).one();
            if (courseRefPoint != null) {
                courseRefPoint.setDesKnowledge(desKnowledge);
                courseRefPointService.updateById(courseRefPoint);
            } else {
                throw new RuntimeException("Course ref point not found");
            }
        } catch (RuntimeException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询用户所创建的课程的详细信息，包括对应题库中的题目数量
     * @param userId
     */
    public List<CourseDetailExtRepoDTO> detailRepo(String userId) {
        List<Course> courseList = new Course().selectList(new QueryWrapper<Course>().eq("create_by", userId));
        LinkedList<CourseDetailExtRepoDTO> courseDetailExtRepoDTOS = new LinkedList<>();
        courseList.forEach(course -> {
            CourseDetailExtRepoDTO courseDetailExtRepoDTO = new CourseDetailExtRepoDTO();
            BeanMapper.copy(course, courseDetailExtRepoDTO);
            CourseRepo courseRepo = courseRepoMapper.selectOne(new QueryWrapper<CourseRepo>().eq("course_id", course.getId()));
            if (courseRepo == null) {
                courseDetailExtRepoDTO.setQuestionNum(0);
            } else {
                courseDetailExtRepoDTO.setQuestionNum(quMapper.selectCount(new QueryWrapper<Qu>().eq("repo_id", courseRepo.getRepoId())));
            }
            courseDetailExtRepoDTOS.add(courseDetailExtRepoDTO);
        });
        return courseDetailExtRepoDTOS;
    }

    /**
     * 查询对应课程ID的课程信息，包含对应题库中的所有题目
     * @param courseId
     */
    public CourseDetailExtQuDTO detailQu(String courseId) {
        Course course = courseMapper.selectById(courseId);
        CourseDetailExtQuDTO courseDetailExtQuDTO = new CourseDetailExtQuDTO();
        BeanMapper.copy(course, courseDetailExtQuDTO);
        CourseRepo courseRepo = courseRepoMapper.selectOne(new QueryWrapper<CourseRepo>().eq("course_id", courseId));
        if (courseRepo == null) {
            courseDetailExtQuDTO.setQuList(new LinkedList<>());
        } else {
            String repoId = courseRepo.getRepoId();
            courseDetailExtQuDTO.setQuList(quMapper.selectList(new QueryWrapper<Qu>().eq("repo_id", repoId)));
        }
        return courseDetailExtQuDTO;
    }
    @Override
    public KnowledgePointDTO getCourseKnowledgePoint(KnowledgePointDTO knowledgePointDTO) {
        try {
            String courseId = knowledgePointDTO.getCourseId();
            CourseRefPoint courseRefPoint = courseRefPointService.lambdaQuery().eq(CourseRefPoint::getCourseId, courseId).one();
            if (courseRefPoint != null) {
                knowledgePointDTO.setPoint(courseRefPoint.getDesKnowledge());
                return knowledgePointDTO;
            } else {
                throw new RuntimeException("Course ref point not found");
            }
        } catch (RuntimeException e) {
            throw new RuntimeException(e);
        }
    }
}
